package mc.support.crawler;

import org.apache.commons.lang.StringUtils;
import org.htmlcleaner.ContentNode;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;

/**
 * Created with IntelliJ IDEA. <br/>
 * User: francis    <br/>
 * Date: 13-11-5    <br/>
 * Time: 17:52  <br/>
 */
public class HtmlParser {

    private static Logger log = LoggerFactory.getLogger( HtmlParser.class );

    public static final String DEFAULT_CHARSET = "utf8";
    public static final String ITEM_ID = "item id";
    public static final String PAGE_INDEX = "page index";
    public static final String INDEX_IN_PAGE = "index in page";

    public static final String VOLUME_SUFFIX = new String(
            new byte[] { (byte)-28, (byte)-70, (byte)-70 } );

    public List<Map<String, Object>> parseSearchResultPage( int pageIndex, String html )
            throws IOException, XPatherException {
        return parseSearchResultPage( pageIndex, html, DEFAULT_CHARSET );
    }

    public Map<Long, Long> parseVolumes( int pageIndex, String html)
            throws IOException, XPatherException {
        return parseVolumes( pageIndex, html, DEFAULT_CHARSET );
    }

    @Deprecated
    public Map<Long, Long> parseVolumes( int pageIndex, String html, String charset )
            throws IOException, XPatherException {
        HtmlCleaner cleaner=new HtmlCleaner();
        TagNode node = cleaner.clean( new BufferedInputStream(
                new ByteArrayInputStream( html.getBytes() ) ), charset );

        Map<Long, Long> map = new HashMap<Long, Long>();

        Object[] volumeNodes = node.evaluateXPath( "//div[@class='col dealing']");
        Object[] idNodes =node.evaluateXPath("//h3[@class='summary']/a");
        for ( int i = 0; i < idNodes.length && i < volumeNodes.length; i++ ) {
            TagNode volumeNode = (TagNode) volumeNodes[i];
            TagNode idNode = (TagNode) idNodes[i];
            String title = volumeNode.getAttributeByName("title");
            String href = idNode.getAttributeByName("href");
            try {
                if ( null == title ) {
                     List<Object> children = volumeNode.getAllChildren();
                    if ( null != children && children.size() > 1 ) {
                        volumeNode = (TagNode) children.get( 1 );
                        children = volumeNode.getAllChildren();
                        if ( null != children && children.size() > 0 ) {
                            ContentNode n = (ContentNode) children.get( 0 );
                            title = n.getContent();
                        }
                    }
                }
                if ( StringUtils.isNotBlank( title ) && StringUtils.isNotBlank( href) ) {
                    String itemIDStr = getItemIdFromHref( href, pageIndex );
                    String volumeStr = getVolumeFromTitle( title );

                    if ( StringUtils.isNumeric( itemIDStr ) && StringUtils.isNumeric( volumeStr ) ) {
                        map.put( Long.valueOf( itemIDStr ), Long.valueOf( volumeStr ) );
                    }
                }
            } catch (Exception e) {
                //ensure part of the result can be returned
            }
        }

        return map;
    }

    public List<Elite> parseVolumes0( int pageIndex, String html, String charset )
            throws IOException, XPatherException {
        HtmlCleaner cleaner=new HtmlCleaner();
        TagNode node = cleaner.clean( new BufferedInputStream(
                new ByteArrayInputStream( html.getBytes() ) ), charset );

        List<Elite> elites = new LinkedList<>();
        Object[] volumeNodes = node.evaluateXPath( "//div[@class='col end dealing']");
        if ( null == volumeNodes || 0 == volumeNodes.length ) {
            volumeNodes = node.evaluateXPath( "//div[@class='col dealing']/div" );
        }
        Object[] idNodes =node.evaluateXPath("//h3[@class='summary']/a");
//        Object[] clsNodes = node.evaluateXPath("//div[@class='col seller feature-dsi-tgr']");
        Object[] clsNodes = node.evaluateXPath("//div[@class='col seller feature-dsc-tgr']");
        if ( null == clsNodes || 0 == clsNodes.length ) {
            clsNodes = node.evaluateXPath( "//a[@class='feature-dsc-tgr']" );
        }
        for ( int i = 0; i < idNodes.length && i < volumeNodes.length; i++ ) {
            TagNode volumeNode = (TagNode) volumeNodes[i];
            TagNode idNode = (TagNode) idNodes[i];
            String dataParam = null;
            if ( i <= clsNodes.length - 1 ) {
                dataParam = ((TagNode) clsNodes[i]).getAttributeByName("data-param");
            }
//            String title = volumeNode.getAttributeByName("title");
            String volumeStr = volumeNode.getText().toString();
            String href = idNode.getAttributeByName("href");
            try {
                if ( null == volumeStr ) {
                    List<Object> children = volumeNode.getAllChildren();
                    if ( null != children && children.size() > 1 ) {
                        volumeNode = (TagNode) children.get( 1 );
                        children = volumeNode.getAllChildren();
                        if ( null != children && children.size() > 0 ) {
                            ContentNode n = (ContentNode) children.get( 0 );
                            volumeStr = n.getContent();
                        }
                    }
                }
                if ( StringUtils.isNotBlank( volumeStr ) && StringUtils.isNotBlank( href) ) {
                    String itemIDStr = getItemIdFromHref( href, pageIndex );
//                    String volumeStr = getVolumeFromTitle( title );
                    volumeStr = volumeStr != null ? volumeStr.replaceAll("\\D+", "") : null;

                    if ( StringUtils.isNumeric( itemIDStr ) && StringUtils.isNumeric( volumeStr ) ) {
                        Elite elite = new Elite();
                        elite.put( "iid", itemIDStr );
                        elite.put( "volume", volumeStr );
                        elite.put( "data_param", dataParam );
                        elites.add( elite );
                    }
                }
            } catch (Exception e) {
                //ensure part of the result can be returned
            }
        }

        return elites;
    }

    @Deprecated
    public List<Elite> parseVolumesOld( int pageIndex, String html, String charset )
            throws IOException, XPatherException {
        HtmlCleaner cleaner=new HtmlCleaner();
        TagNode node = cleaner.clean( new BufferedInputStream(
                new ByteArrayInputStream( html.getBytes() ) ), charset );

        List<Elite> elites = new LinkedList<>();
        Object[] volumeNodes = node.evaluateXPath( "//div[@class='col dealing']");
        Object[] idNodes =node.evaluateXPath("//h3[@class='summary']/a");
        Object[] clsNodes = node.evaluateXPath("//div[@class='col seller feature-dsi-tgr']");
        for ( int i = 0; i < idNodes.length && i < volumeNodes.length; i++ ) {
            TagNode volumeNode = (TagNode) volumeNodes[i];
            TagNode idNode = (TagNode) idNodes[i];
            String dataParam = null;
            if ( i <= clsNodes.length - 1 ) {
                dataParam = ((TagNode) clsNodes[i]).getAttributeByName("data-param");
            }
            String title = volumeNode.getAttributeByName("title");
            String href = idNode.getAttributeByName("href");
            try {
                if ( null == title ) {
                    List<Object> children = volumeNode.getAllChildren();
                    if ( null != children && children.size() > 1 ) {
                        volumeNode = (TagNode) children.get( 1 );
                        children = volumeNode.getAllChildren();
                        if ( null != children && children.size() > 0 ) {
                            ContentNode n = (ContentNode) children.get( 0 );
                            title = n.getContent();
                        }
                    }
                }
                if ( StringUtils.isNotBlank( title ) && StringUtils.isNotBlank( href) ) {
                    String itemIDStr = getItemIdFromHref( href, pageIndex );
                    String volumeStr = getVolumeFromTitle( title );

                    if ( StringUtils.isNumeric( itemIDStr ) && StringUtils.isNumeric( volumeStr ) ) {
                        Elite elite = new Elite();
                        elite.put( "iid", itemIDStr );
                        elite.put( "volume", volumeStr );
                        elite.put( "data_param", dataParam );
                        elites.add( elite );
                    }
                }
            } catch (Exception e) {
                //ensure part of the result can be returned
            }
        }

        return elites;
    }

    public List<Map<String, Object>> parseSearchResultPage( int pageIndex, String html, String charset )
            throws IOException, XPatherException {

        HtmlCleaner cleaner=new HtmlCleaner();
        TagNode node = cleaner.clean( new BufferedInputStream(
                new ByteArrayInputStream( html.getBytes() ) ), charset );

        //TagNode[] titleNode = node.getElementsByName( "title", true );

//        if( titleNode.length > 0 ){
//            log.info( "title--" + titleNode[0].getText() );
//        }

        List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
        Object[] tagNodes =node.evaluateXPath("//h3[@class='summary']/a");//使用xpath方式提取标记

        for ( int indexIndexPage=0; indexIndexPage< tagNodes.length; indexIndexPage++ ) {
            TagNode tagNode = (TagNode)tagNodes[indexIndexPage];
            String href = tagNode.getAttributeByName("href");
            resultList.add( parseSingleItem( href, pageIndex, indexIndexPage ) );
        }

        return resultList;
    }

    private Map<String, Object> parseSingleItem( String href, int pageIndex, int indexInPage ) {
        String itemId = getItemIdFromHref( href, pageIndex );
//        String itemId = null;
//        try {
//            itemId = getItemIdFromHerf( href );
//        } catch (Exception e) {
//            log.warn( "get item id from herf fail!" );
//        }
        Map<String, Object> singleResult = new HashMap<String, Object>(4);
        singleResult.put( ITEM_ID, itemId );
        singleResult.put( PAGE_INDEX, pageIndex + 1 );
        singleResult.put( INDEX_IN_PAGE, indexInPage + 1 );

        return singleResult;
    }

    private String getItemIdFromHerf(String href) {
        String id = null;
        int begin = href.indexOf( "id=" );
        if ( begin > 0 ) {
            if ('?' == href.charAt( begin - 1 ) ||
                    '&' == href.charAt( begin -1 ) ) {
                begin += 3;
                int end = begin;
                while ( end <= href.length() &&
                        Character.isDigit( href.charAt( end ) ) ) {
                    end++;
                }
                while ( ++end < href.length() ) {
                    if ( !Character.isDefined( href.charAt( end ) )) {
                        break;
                    }
                }
                id = href.substring( begin, end );
            } else {
                id = getItemIdFromHerf( href.substring( begin + 3 ) );
            }
        } else if ( 0 == begin ) {
            id = getItemIdFromHerf( href.substring( 3 ) );
        }
        return id;
    }

    private String getItemIdFromHref(String href, int pageIndex) {
        String itemId = null;

        if( 0 == pageIndex && href.indexOf("&") > 0 ) { //首页44个产品，处理最前三个特殊连接
            itemId = href.substring( href.indexOf("id=") + 3 , href.indexOf("&") );
        }
        if ( 0 == pageIndex && href.indexOf("&") <= 0 ) {
            itemId = href.substring( href.indexOf("id=") + 3 );
        }
        if ( pageIndex > 0 ){
            itemId = href.substring( href.indexOf("id=") + 3 );
        }

        return itemId;
    }

    private String getVolumeFromTitle(String title) {
        String[] ss = title.split("\\s+");
        String result = null;
        if ( ss.length > 1 ) {
            int index = ss[1].indexOf( VOLUME_SUFFIX );
            if ( index >0 ) {
                result = ss[1].substring(0, index);
            }
        }
        return result;
    }

}